/*******************************************************************************
	RDMA server module
*******************************************************************************/
#include "main.h"

const int mBufSize = 32 * 1024 * 1024;

int totalRDMARecv = 0;
static int iCount = 0;
uint32_t srvBufPos = 0;
uint32_t bytesBufRemaining = 0;

static byte srvBuffer[33554432];
static Instruction mInstructions[MAX_INSTRUCTIONS];

RDMASrvModule::RDMASrvModule(int port)
{
	rdmaUtil = new RDMAUtil(EP_SERVER, port);
}

bool RDMASrvModule::process(vector<Instruction *> *list)
{
	uint32_t num = 0;
	
	iCount = 0;

	int len = internalRead((byte *)&num, sizeof(uint32_t));
	if (len != sizeof(uint32_t)) {
		LOG("Read error\n");
		return false;
	}
	
	for (uint32_t x=0;x<num;x++) {
		Instruction *i = &mInstructions[iCount++];
		
		int l = sizeof(Instruction);
		int r = internalRead((byte *)i, l);
		if(r != l) {
			LOG("Read error 2 (%d, %d)\n", r, l);
			return false;
		}

		//Now see if we're expecting any buffers
		for (int n=0;n<3;n++) {
			int l = i->buffers[n].len;
			if(l > 0) {				
				i->buffers[n].buffer = (byte *) malloc(l);
				i->buffers[n].needClear = true;				
				i->buffers[n].needRemoteReply = i->buffers[n].needReply;
				internalRead(i->buffers[n].buffer, l);						
			}
		}		
	
		list->push_back(i);
	}

	if (totalRDMARecv == 0) {
		LOG("Connection dropped\n");
		SDL_Quit();
		return false;
	}
	
	Stats::count("mod_rdmasrv read bytes", totalRDMARecv);
	Stats::increment("mod_rdmasrv read bytes", totalRDMARecv);
	
	totalRDMARecv = 0;
	return true;
}


void RDMASrvModule::reply(Instruction *instr, int i)
{
	if (instr->id == 256) {
    	internalWrite(instr->buffers[i].buffer, 5);
	} else {
		internalWrite(instr->buffers[i].buffer, instr->buffers[i].len);
	}
}

bool RDMASrvModule::sync()
{
	return true;
}

int RDMASrvModule::internalRead(byte *input, int nByte)
{
	if (bytesBufRemaining <= 0 && recieveBuffer() < 0) {
		return -1;
	}
	
	memcpy(input, srvBuffer + srvBufPos, nByte);
	

	srvBufPos += nByte;
	bytesBufRemaining -= nByte;

	return nByte;
}


int RDMASrvModule::recieveBuffer(void)
{
	if (gConfig->networkCompression) {
		bytesBufRemaining = rdmaUtil->recv2(Compression::getBuf());
		if(bytesBufRemaining < 0) return -1;
		totalRDMARecv += bytesBufRemaining;
		bytesBufRemaining = Compression::decompress(srvBuffer, mBufSize, bytesBufRemaining);
	} else {
		bytesBufRemaining = rdmaUtil->recv2(srvBuffer);
		if(bytesBufRemaining < 0) return -1;
		totalRDMARecv += bytesBufRemaining;
	}

	srvBufPos = 0;
	return 0;
}

int RDMASrvModule::internalWrite(byte *input, int nByte)
{
	return rdmaUtil->send2(input, nByte);
}

int RDMASrvModule::writeFrame(byte *frame, int size)
{
	int ret;
	if(frame == NULL || size == 0){
		ret = rdmaUtil->send_length(0);
	} else {
		ret = rdmaUtil->send2(frame, size);
	}
	if(ret < 0)
		LOG("Failed to send frame to client\n");

	return ret;
}
